package com.zycfc.zsf.boot.distributedlock;

import com.zycfc.zsf.boot.distributedlock.zk.util.*;
import com.zycfc.zsf.boot.util.text.*;
import com.zycfc.zsf.boot.distributedlock.zk.comparator.*;
import org.I0Itec.zkclient.exception.*;
import com.zycfc.zsf.boot.distributedlock.zk.listener.*;
import org.I0Itec.zkclient.*;
import java.util.concurrent.*;
import java.util.*;
import org.slf4j.*;

public class DistributedZkLock implements IDistributedLock
{
    private static final Logger log;
    private ZkClient zkClient;
    private static final String ZK_LOCK_BASE_PATH = "/distributed-zk-lock";
    private String zkLockGroupNode;
    private String zkLockGroupPath;
    private String zkLockNodePre;
    private String zkLockNodePrePath;
    private String zkLockNodePath;
    private Integer reTryCount;
    private Long waitTime;
    private static final Integer DEFAULT_RETRY_COUNT;
    private static final Long DEFAULT_WAIT_TIME;
    private static final String ZK_LOCK_GROUP_NODE_DESC = "zk\u9501\u5206\u7ec4\u8282\u70b9\u540d\u79f0";
    private static final String ZK_LOCK_NODE_PRE_DESC = "zk\u9501\u8282\u70b9\u540d\u79f0\u524d\u7f00";
    private static final String NODE_NOT_EXISTS = "\u8282\u70b9\u4e0d\u5b58\u5728\uff01";
    private static final String ZK_NODE_SEPARATOR = "/";
    
    public String getZkLockNodePre() {
        return this.zkLockNodePre;
    }
    
    public DistributedZkLock(final String zkServers, final String namespace, final int flag) {
        this.zkClient = ZkClientUtil.getNewZkClient(zkServers);
        this.zkLockGroupNode = namespace;
        this.zkLockGroupPath = new StringBuffer("/distributed-zk-lock").append("/").append(this.zkLockGroupNode).toString();
        this.zkLockNodePrePath = this.zkLockGroupPath + "/" + this.zkLockNodePre;
        this.reTryCount = DistributedZkLock.DEFAULT_RETRY_COUNT;
        this.waitTime = DistributedZkLock.DEFAULT_WAIT_TIME;
    }
    
    public DistributedZkLock(final String zkLockGroupNodeName, final String zkLockNodePre) {
        this(zkLockGroupNodeName, zkLockNodePre, DistributedZkLock.DEFAULT_RETRY_COUNT, DistributedZkLock.DEFAULT_WAIT_TIME);
    }
    
    private DistributedZkLock(final String zkLockGroupNode, final String zkLockNodePre, final Integer reTryCount, final Long waitTime) {
        CheckUtil.notNull((Object)zkLockGroupNode, "zk\u9501\u5206\u7ec4\u8282\u70b9\u540d\u79f0");
        CheckUtil.notNull((Object)zkLockNodePre, "zk\u9501\u8282\u70b9\u540d\u79f0\u524d\u7f00");
        this.zkClient = ZkClientUtil.getNewZkClient();
        this.zkLockGroupNode = zkLockGroupNode;
        this.zkLockGroupPath = new StringBuffer("/distributed-zk-lock").append("/").append(zkLockGroupNode).toString();
        this.zkLockNodePrePath = this.zkLockGroupPath + "/" + zkLockNodePre;
        this.zkLockNodePre = zkLockNodePre;
        this.reTryCount = reTryCount;
        this.waitTime = waitTime;
    }
    
    private String getZkLockGroupPath() {
        return this.zkLockGroupPath;
    }
    
    private String getZkLockPath() {
        return this.zkLockNodePrePath;
    }
    
    private void setZkLockNodePath(final String zkLockNodePath) {
        this.zkLockNodePath = zkLockNodePath;
    }
    
    public void setWaitTime(final Long waitTime) {
        this.waitTime = waitTime;
    }
    
    @Override
    public boolean tryLock(final String key) {
        return false;
    }
    
    @Override
    public boolean tryLock() {
        boolean hasTheLock = false;
        CheckUtil.notNull((Object)this.zkLockGroupNode, "zk\u9501\u5206\u7ec4\u8282\u70b9\u540d\u79f0");
        CheckUtil.notNull((Object)this.zkLockNodePre, "zk\u9501\u8282\u70b9\u540d\u79f0\u524d\u7f00");
        do {
            try {
                ZkClientUtil.createIfNotExists(this.zkClient, this.zkLockGroupPath);
                final String lockNode = ZkClientUtil.createEphemeralSequential(this.zkClient, this.zkLockNodePrePath);
                this.setZkLockNodePath(lockNode);
                hasTheLock = this.acquireLock(this.zkClient, lockNode);
            }
            catch (Exception e) {
                DistributedZkLock.log.error("tryLock zkLockNodePre:{},Exception:", (Object)this.zkLockNodePre, (Object)e);
            }
            if (hasTheLock) {
                break;
            }
            final Integer reTryCount = this.reTryCount;
            --this.reTryCount;
        } while (this.reTryCount >= 0);
        return hasTheLock;
    }
    
    public boolean acquireLock(final ZkClient zkClient, final String lockNode) throws Exception {
        boolean acquireTheLock = false;
        boolean shouldDelete = false;
        final Long startTimeMillis = System.currentTimeMillis();
        CountDownLatch countDownLatch = null;
        try {
            do {
                final List<String> childNodeList = ZkClientUtil.getChildNodeList(zkClient, this.zkLockGroupPath);
                childNodeList.stream();
                Collections.sort(childNodeList, new LockNodeComparator(this.zkLockNodePre));
                final String lockNodeSequence = lockNode.substring(this.zkLockGroupPath.length() + 1);
                final int lockNodeIndex = childNodeList.indexOf(lockNodeSequence);
                if (lockNodeIndex < 0) {
                    throw new ZkNoNodeException(lockNodeSequence + "\u8282\u70b9\u4e0d\u5b58\u5728\uff01");
                }
                acquireTheLock = (lockNodeIndex == 0);
                if (acquireTheLock || CheckUtil.isNull((Object)this.waitTime) || this.waitTime == 0L) {
                    return acquireTheLock;
                }
                final String previousNode = childNodeList.get(lockNodeIndex - 1);
                final String previousNodePath = this.zkLockGroupPath + "/" + previousNode;
                countDownLatch = new CountDownLatch(1);
                zkClient.subscribeDataChanges(previousNodePath, (IZkDataListener)new ZkLockDataListener(countDownLatch));
                if (CheckUtil.isNotNull((Object)this.waitTime)) {
                    this.waitTime -= System.currentTimeMillis() - startTimeMillis;
                    if (this.waitTime <= 0L) {
                        shouldDelete = true;
                        break;
                    }
                }
                if (!zkClient.exists(previousNodePath)) {
                    continue;
                }
                DistributedZkLock.log.info("lockNode{}\u51c6\u5907await previousNodePath:{}", (Object)lockNode, (Object)previousNodePath);
                countDownLatch.await(this.waitTime, TimeUnit.MILLISECONDS);
            } while (CheckUtil.isNotNull((Object)this.waitTime) && this.waitTime > 0L);
        }
        catch (Exception e) {
            shouldDelete = true;
            throw e;
        }
        finally {
            if (shouldDelete) {
                ZkClientUtil.delete(zkClient, lockNode);
            }
        }
        return acquireTheLock;
    }
    
    @Override
    public boolean releaseLock(final String key) {
        return false;
    }
    
    @Override
    public boolean releaseLock() {
        DistributedZkLock.log.info("\u5c06\u8981\u5220\u9664zk\u8282\u70b9:{},Thread:{}", (Object)this.zkLockNodePath, (Object)Thread.currentThread().getName());
        return ZkClientUtil.delete(this.zkClient, this.zkLockNodePath);
    }
    
    public ZkClient getZkClient() {
        return this.zkClient;
    }
    
    public String getZkLockGroupNode() {
        return this.zkLockGroupNode;
    }
    
    public String getZkLockNodePrePath() {
        return this.zkLockNodePrePath;
    }
    
    public String getZkLockNodePath() {
        return this.zkLockNodePath;
    }
    
    public Integer getReTryCount() {
        return this.reTryCount;
    }
    
    public Long getWaitTime() {
        return this.waitTime;
    }
    
    static {
        log = LoggerFactory.getLogger((Class)DistributedZkLock.class);
        DEFAULT_RETRY_COUNT = 1;
        DEFAULT_WAIT_TIME = 0L;
    }
}
